﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using System.Xml;
using ApplicationGenerator.BusinessModule.MetaElements;
using ApplicationGenerator.CommonModule;
using ApplicationGenerator.DataAccess;
using ApplicationGenerator.Forms.WebControls;
using ApplicationGenerator.GeneratorMenu.BusinessLogic;
using ApplicationGenerator.Lists.BusinessLogic;
using Castle.ActiveRecord;
using Castle.ActiveRecord.Framework.Config;
using WeifenLuo.WinFormsUI.Docking;
using System.CodeDom.Compiler;
using System.Text;

namespace GUserInterface
{
    public partial class MainForm : Form
    {

        #region Variables

        private SolutionExplorer solutionExp = new SolutionExplorer();
        private PropertyGrid propertyGrid = new PropertyGrid();
        private ControlsToolbox controlsTbx = new ControlsToolbox();
        private ToolboxService workflowTbx;
        private ErrorList errorList = new ErrorList();
        private MetaModelManager metamanager = MetaModelManager.Instance;

        #endregion

        #region Construction

        /// <summary>
        /// default contructor
        /// </summary>
        public MainForm()
        {
            InitializeComponent();
            InitializeComponent_Custom();
        }

        /// <summary>
        /// Custom initialization of components
        /// </summary>
        private void InitializeComponent_Custom()
        {
            //init all menus, toolboxes and so on ...
            errorList.Show(dockPanel1, WeifenLuo.WinFormsUI.Docking.DockState.DockBottom);
            solutionExp.Show(dockPanel1, WeifenLuo.WinFormsUI.Docking.DockState.DockBottom);
            propertyGrid.Show(dockPanel1, WeifenLuo.WinFormsUI.Docking.DockState.DockRight);
            controlsTbx.ShowToolbox(false);
            controlsTbx.Show(dockPanel1, WeifenLuo.WinFormsUI.Docking.DockState.DockLeft);

            AddEventHandlers();
        }

        /// <summary>
        /// Adds event handlers for main form
        /// </summary>
        private void AddEventHandlers()
        {
            dockPanel1.ActiveDocumentChanged += new EventHandler(dockPanel1_ActiveDocumentChanged);
            controlsTbx.VisibleChanged += new EventHandler(gToolbox_VisibleChanged);
            propertyGrid.VisibleChanged += new EventHandler(gToolbox_VisibleChanged);
            solutionExp.VisibleChanged += new EventHandler(gToolbox_VisibleChanged);
            solutionExp.TreeViewClickedEvent += new TreeViewClickedHandler(solutionExp_SolutionExpClickExecHandler);
        }

        #endregion

        #region Methods

        private void solutionExp_SolutionExpClickExecHandler(string title, Policy policy)
        {
            IDockContent dockContent = null;
            if (null != (dockContent = FindFormVEPanel(title)))
            {
                propertyGrid.mPropertyGrid.SelectedObject = dockContent;
            }
            else
            {
                DockContent panel = null;

                //deserialize and open..
                switch (policy)
                {
                    case Policy.Form:
                        panel = CreateFormVEPanel(title);
                        break;
                    case Policy.List:
                        panel = CreateListVEPanel(title);
                        break;
                    case Policy.Workflow:
                        panel = CreateWorkflowPanel(title);
                        panel.AllowDrop = true;
                        workflowTbx = ((WorkflowPanel)panel).wdc.Toolbox;
                        workflowTbx.Show(dockPanel1, WeifenLuo.WinFormsUI.Docking.DockState.DockLeft);
                        break;
                    case Policy.Menu:
                        panel = CreateMenuPanel();
                        break;
                }

                if (null != panel)
                {
                    panel.Show(dockPanel1);
                }
            }
        }

        private void gToolbox_VisibleChanged(object sender, EventArgs args)
        {
            Form frm = (Form)sender;
            Type type = ((Form)sender).GetType();

            if (typeof(SolutionExplorer) == type)
            {
                if (false == frm.Visible)
                {
                    solutionExpToolStripMenuItem.Checked = false;
                }
                else
                {
                    solutionExpToolStripMenuItem.Checked = true;
                }
            }
            else if (typeof(PropertyGrid) == type)
            {
                if (false == frm.Visible)
                {
                    propertyGridToolStripMenuItem.Checked = false;
                }
                else
                {
                    propertyGridToolStripMenuItem.Checked = true;
                }
            }
            else if (typeof(ControlsToolbox) == type)
            {
                if (false == frm.Visible)
                {
                    controlsToolboxToolStripMenuItem.Checked = false;
                }
                else
                {
                    controlsToolboxToolStripMenuItem.Checked = true;
                }
            }

        }

        /// <summary>
        /// Indicates if Control Toolbox should be enabled
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void dockPanel1_ActiveDocumentChanged(object sender, EventArgs args)
        {
            if (null != dockPanel1.ActiveDocument && typeof(FormVEPanel) == dockPanel1.ActiveDocument.GetType())
            {
                controlsTbx.ShowToolbox(true);
            }
            else
            {
                controlsTbx.ShowToolbox(false);
            }
            controlsTbx.Refresh();
        }

        private void SolutionExplorerToolStripMenuItem_Click(object sender, EventArgs e)
        {

            if (true == solutionExpToolStripMenuItem.Checked)
            {
                solutionExp.Show(dockPanel1);
            }
            else
            {
                solutionExp.Hide();
            }
        }

        private void PropertyGridToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (true == propertyGridToolStripMenuItem.Checked)
            {
                propertyGrid.Show(dockPanel1);
            }
            else
            {
                propertyGrid.Hide();
            }
        }

        private void contorlsToolboxToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (true == controlsToolboxToolStripMenuItem.Checked)
            {
                if (null == controlsTbx)
                {
                    controlsTbx = new ControlsToolbox();
                }
                controlsTbx.Show(dockPanel1, WeifenLuo.WinFormsUI.Docking.DockState.DockLeft);
            }
            else
            {
                if (null != controlsTbx)
                {
                    controlsTbx.Hide();
                }
            }

        }

        /// <summary>
        /// handler creates new asp.net form
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void formToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FormVEPanel panel = null;

            if (null != (panel = CreateNewFormVEPanel()))
            {
                panel.Show(dockPanel1);
            }
        }


        private MenuVEPanel CreateMenuPanel()
        {
            ApplicationMenu appMenu = (ApplicationMenu)Serializer.Deserialize(Policy.Menu, "menu");
            MenuVEPanel panel = null;

            if (appMenu != null)
            {
                panel = new MenuVEPanel(appMenu);
            }
            else
            {
                panel = new MenuVEPanel();
            }

            //add event handlers for this form

            panel.Text = "Menu";
            panel.TabText = "Menu";

            return panel;
        }

        private FormVEPanel CreateFormVEPanel(string title)
        {
            FormControlContainer fcc = (FormControlContainer)ApplicationGenerator.DataAccess.Serializer.Deserialize(ApplicationGenerator.DataAccess.Policy.Form, title);

            FormVEPanel panel = new FormVEPanel(fcc);

            //add event handlers for this form
            panel.FEPanel.fephEvent += new VisualEditorUILib.FormEditorPanelHandler(fephEventHandler);
            panel.RefreshEvent += new RefreshHandler(refreshPanelHandler);
            panel.UpdatePropertyGridEvent += new UpdatePropertyGridHandler(updatePropertyGrid);
            panel.FormSavedEvent += new FormSaved(panel_FormSavedEvent);
            panel.ValidationFailedEvent += new ValidationFailedHandler(panel_ValidationFailedEventHandler);

            panel.Text = title;
            panel.TabText = title;
            return panel;
        }

        public ListVEPanel CreateNewListVEPanel()
        {

            int count = 0;
            string title = "list" + solutionExp.GetNumOfDocuments(Policy.List);

            while (null != FindFormVEPanel(title))
            {
                count++;
                title = "list" + count.ToString();
            }

            NewListDlg dlg = new NewListDlg(title);
            dlg.ShowDialog();

            if (dlg.DialogResult != DialogResult.OK)
            {
                return null;
            }

            title = dlg.Title;

            ListVEPanel panel = new ListVEPanel();


            //add event handlers for this form
            panel.ListSavedEvent += new ListSaved(panel_ListSavedEvent);

            panel.Text = title;
            panel.TabText = title;
            return panel;
        }

        private ListVEPanel CreateListVEPanel(string title)
        {
            ListConfiguration listConfig = (ListConfiguration)Serializer.Deserialize(Policy.List, title);

            ListVEPanel panel = new ListVEPanel(listConfig);


            //add event handlers for this form
            panel.ListSavedEvent += new ListSaved(panel_ListSavedEvent);

            panel.Text = title;
            panel.TabText = title;
            return panel;
        }

        /// <summary>
        /// creates new form of visual editor of asp.net form
        /// </summary>
        /// <returns></returns>
        private FormVEPanel CreateNewFormVEPanel()
        {
            //int count = 0;
            int rows = 0;
            int cols = 0;
            string title = string.Empty;
            title = "form" + solutionExp.GetNumOfDocuments(Policy.Form);

            NewFormDlg dlg = new NewFormDlg(title);

            if (DialogResult.OK == dlg.ShowDialog())
            {
                cols = dlg.NumOfCols;
                rows = dlg.NumOfRows;
                title = dlg.Title;
            }
            else
            {
                return null;
            }

            FormVEPanel panel = new FormVEPanel(rows, cols, metamanager.MetaModelCollection[dlg.SourceName]);

            //add event handlers for this form
            panel.FEPanel.fephEvent += new VisualEditorUILib.FormEditorPanelHandler(fephEventHandler);
            panel.RefreshEvent += new RefreshHandler(refreshPanelHandler);
            panel.UpdatePropertyGridEvent += new UpdatePropertyGridHandler(updatePropertyGrid);
            panel.FormSavedEvent += new FormSaved(panel_FormSavedEvent);
            panel.ValidationFailedEvent += new ValidationFailedHandler(panel_ValidationFailedEventHandler);

            panel.Text = title;
            panel.TabText = title;
            return panel;
        }

        /// <summary>
        /// creates new form of visual editor of asp.net form
        /// </summary>
        /// <returns></returns>
        private WorkflowPanel CreateNewWorkflowPanel()
        {
            int count = 0;

            string title = "flow" + solutionExp.GetNumOfDocuments(Policy.Workflow);
            while (null != FindFormVEPanel(title))
            {
                count++;
                title = "flow" + count;
            }

            NewFlowDlg dlg = new NewFlowDlg(title);
            dlg.ShowDialog();

            if (dlg.DialogResult != DialogResult.OK)
            {
                return null;
            }
            title = dlg.Title;
            WorkflowPanel panel = new WorkflowPanel();
            panel.Dock = DockStyle.Fill;
            panel.Text = title;
            panel.TabText = title;
            panel.UpdatePropertyGridEvent += new UpdatePropertyGridHandler(updatePropertyGrid_multiple);
            panel.WorkflowSavedEvent += new WorkflowSaved(panel_WorkflowSavedEvent);

            return panel;
        }


        /// <summary>
        /// creates new form of visual editor of asp.net form
        /// </summary>
        /// <returns></returns>
        private WorkflowPanel CreateWorkflowPanel(string title)
        {
            byte[] xoml = (byte[])Serializer.Deserialize(Policy.Workflow, title);
            System.Text.Encoding encoding = System.Text.Encoding.ASCII;
            string xomlString = encoding.GetString(xoml);

            WorkflowPanel panel = new WorkflowPanel(xomlString);

            panel.UpdatePropertyGridEvent += new UpdatePropertyGridHandler(updatePropertyGrid_multiple);
            panel.WorkflowSavedEvent += new WorkflowSaved(panel_WorkflowSavedEvent);
            panel.Dock = DockStyle.Fill;
            panel.Text = title;
            panel.TabText = title;

            return panel;
        }

        void panel_ListSavedEvent(string title)
        {
            solutionExp.AddSolutionNode(title, Policy.List);
        }

        void panel_WorkflowSavedEvent(string title)
        {
            solutionExp.AddSolutionNode(title, Policy.Workflow);
        }

        private void panel_FormSavedEvent(string title)
        {
            solutionExp.AddSolutionNode(title, Policy.Form);
        }

        private void panel_ValidationFailedEventHandler(List<ErrorEntity> errorEntities)
        {
            errorList.FillErrorList(errorEntities);
        }

        private void updatePropertyGrid(object toUpdate)
        {
            propertyGrid.mPropertyGrid.SelectedObject = toUpdate;
        }

        private void updatePropertyGrid_multiple(object toUpdate)
        {
            propertyGrid.mPropertyGrid.SelectedObjects = (object[])toUpdate;
        }

        private void refreshPanelHandler(string OldName)
        {
            Form form = (Form)FindFormVEPanel(OldName);
            form.Refresh();
        }

        private void fephEventHandler(BaseControl bc)
        {
            propertyGrid.mPropertyGrid.SelectedObject = bc;
        }

        private IDockContent FindFormVEPanel(string text)
        {
            if (dockPanel1.DocumentStyle == DocumentStyle.DockingMdi)
            {
                foreach (Form form in MdiChildren)
                {
                    if (form.Text == text)
                    {
                        return (IDockContent)form;
                    }
                }

                return null;
            }
            else
            {
                foreach (IDockContent content in dockPanel1.Documents)
                {
                    if (content.DockHandler.TabText == text)
                    {
                        return content;
                    }
                }

                return null;
            }
        }

        private void MainForm_Shown(object sender, EventArgs e)
        {
            WelcomeDialog welcome = new WelcomeDialog();
            if (DialogResult.OK != welcome.ShowDialog())
            {
                this.Close();
            }
            else
            {
                SolutionDlg dlg = new SolutionDlg(welcome.CSType);
                //dlg.FormClosed += new FormClosedEventHandler(dlg_FormClosed);

                if (DialogResult.OK != dlg.ShowDialog())
                {
                    this.Close();
                }

                if (ProjectType.New == welcome.CSType)
                {
                    //make config file for this project
                    CreateConfigFile(DesignerDataBaseManager.Instance.ConnectionString,
                                     dlg.DirPath,
                                     dlg.ModelsDirectoryPath,
                                     dlg.UserName,
                                     dlg.Passwd,
                                     dlg.DbName);
                }

                ProjectConfiguration.ProjectDirectoryPath = dlg.DirPath;
                try
                {
                    ProjectConfiguration.SetUpProjectConfiguration();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "Błąd konfiguracji projektu", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    Application.Exit();
                }

                try
                {
                    if (File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ActiveRecordConfiguration.AssemblyName)))
                    {
                        //try
                        //{
                        //    File.Delete(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ActiveRecordConfiguration.AssemblyName));
                        //}
                        //catch (Exception ex)
                        //{
                        //    //
                        //}
                    }
                    else
                    {
                        CompilerResults compilerResults = ModelsCompiler.Compile(dlg.ModelsDirectoryPath, AppDomain.CurrentDomain.BaseDirectory);
                        if (compilerResults.Errors.HasErrors)
                        {
                            StringBuilder errorBuilder = new StringBuilder();
                            errorBuilder.AppendLine("W trakcie kompilacji wystąpiły następujące błędy:");
                            foreach (CompilerError oError in compilerResults.Errors)
                            {
                                errorBuilder.AppendLine(oError.ErrorText);
                            }

                            MessageBox.Show(errorBuilder.ToString(), "Błędy kompilacji", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            Application.Exit();
                        }
                    }

                    Assembly modelsAssembly = Assembly.LoadFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ActiveRecordConfiguration.AssemblyName));
                    AssemblyName assemblyName = modelsAssembly.GetName();
                    Assembly assembly = AppDomain.CurrentDomain.Load(assemblyName);

                    InPlaceConfigurationSource source = new InPlaceConfigurationSource();
                    source.Add(typeof(ActiveRecordBase), ActiveRecordConfiguration.GetConfiguration(DesignerDataBaseManager.Instance.ConnectionString));

                    ActiveRecordStarter.Initialize(assembly, source);
                    if (dlg.CreateTables)
                    {
                        ActiveRecordStarter.DropSchema();
                        ActiveRecordStarter.CreateSchema();
                    }

                    if (ProjectType.Old == welcome.CSType)
                    {
                        solutionExp.LoadSolution();
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(string.Format("Problems during loading assembly: {0}", ex.Message), "error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    this.Close();
                }
            }
        }



        #endregion

        #region Helper Methods

        void CreateConfigFile(string connectionString,
                                string dirPath,
                                string assemblyPath,
                                string userName,
                                string passwd,
                                string dbName)
        {
            XmlConfigMaker configMaker = new XmlConfigMaker();

            ConfigEntry connString = new ConfigEntry();
            connString.Name = "ConnectionString";
            connString.Value = connectionString;

            ConfigEntry _userName = new ConfigEntry();
            _userName.Name = "UserName";
            _userName.Value = userName;

            ConfigEntry _passwd = new ConfigEntry();
            _passwd.Name = "Passwd";
            _passwd.Value = passwd;

            ConfigEntry _dbName = new ConfigEntry();
            _dbName.Name = "DbName";
            _dbName.Value = dbName;

            ConfigEntry asmblyLoc = new ConfigEntry();
            asmblyLoc.Name = "AsmblyLocation";
            asmblyLoc.Value = assemblyPath;

            ConfigEntry projectLocation = new ConfigEntry();
            projectLocation.Name = "ProjectLocation";
            projectLocation.Value = dirPath;

            configMaker.AddEntry(connString);
            configMaker.AddEntry(asmblyLoc);
            configMaker.AddEntry(projectLocation);
            configMaker.AddEntry(_userName);
            configMaker.AddEntry(_passwd);
            configMaker.AddEntry(_dbName);

            configMaker.Save(dirPath + "\\config.xml");

        }

        #endregion

        private void dlg_FormClosed(object sender, EventArgs e)
        {
            //this.Close();
        }

        private void flowToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //WorkflowDesignerControl panel = null;
            WorkflowPanel panel = null;

            if (null != (panel = CreateNewWorkflowPanel()))
            {
                panel.Show(dockPanel1);
                panel.AllowDrop = true;
                workflowTbx = panel.wdc.Toolbox;
                workflowTbx.Show(dockPanel1, WeifenLuo.WinFormsUI.Docking.DockState.DockLeft);
            }

        }

        private void openToolStripButton_Click(object sender, EventArgs e)
        {
            ListVEPanel panel = null;

            if (null != (panel = CreateNewListVEPanel()))
            {
                panel.Show(dockPanel1);
            }
        }
    }
}
